package gui;

import java.util.ArrayList;
import android_board.AndroidGUIBoardController;
import android_codebehind.GUIFieldFactory;
import android_fields.AndroidField;
import common.Car;
import common.IGUIField;
import desktop_board.DesktopGUIBoardController;
import desktop_codebehind.FieldFactory;
import desktop_fields.DesktopField;

public class G {
	public static boolean android = true;
	private static AndroidGUIBoardController abc;
	private static DesktopGUIBoardController dbc;
	
	/**
	 * Retrieves the singleton instance.<br>
	 * @return the Board instance
	 */
	static AndroidGUIBoardController getABC() {
		if(abc == null) {
			abc = new AndroidGUIBoardController();
		}
		return abc;
	}
	private static DesktopGUIBoardController getDBC() {
		if(dbc == null) {
			dbc = new DesktopGUIBoardController();
		}
		return dbc;
	}
	
	/**
	 * Closes the GUI, so you can start a new one.
	 */
	public static void close() {
		if(android) {
			getABC().closeGUI();
			abc = null;
			// FieldFactory.path = null;
		} else {
			getDBC().closeGUI();
			dbc = null;
		}
	}
	/**
	 * Displays a message to the user.<br>
	 * Breaks the system until "OK" is pressed.<br>
	 * @param msg The message to print.
	 * @param button The text on the button
	 */
	public static void showMessage(String msg, String button) {
		if(android) getABC().getInput(msg, false, false, null, new String[] {button});
		else getDBC().showMessage(msg, button);
	}
	/**
	 * Displays a message to the user.<br>
	 * Breaks the system until "OK" is pressed.<br>
	 * @param msg The message to print.
	 */
	public static void showMessage(String msg) {
		showMessage(msg, "OK");
	}
	/**
	 * Displays a message, an input-textfield and an "OK"-button
	 * @param msg The message to print<br>
	 * @return the input string
	 */
	public static String getUserString(String msg) {
		if(android) return getABC().getInput(msg, true, false, null, new String[] {"OK"})[0];
		return getDBC().getUserString(msg);
	}
	/**
	 * Displays a message to the user and awaits the button pressed response.<br>
	 * @param msg The message that promts the user.
	 * @param buttons A number of strings that should be printed on the buttons
	 *        the user can press.
	 * @return The string from the button that the user pressed.
	 */
	public static String getUserButtonPressed(String msg, String... buttons) {
		if(android) return getABC().getInput(msg, false, false, null, buttons)[1];
		return getDBC().getUserButtonPressed(msg, buttons).toString();
	}
	/**
	 * Displays a message and a drop down menu
	 * @param msg The message to print
	 * @param items Elements in the drop down menu
	 * @return the selected item
	 */
	public static String getUserDropDownSelection(String msg, String[] items) {
		if(android) {
			return getABC().getInput(msg, false, true, items, new String[] {"OK"})[2];
		}
		return getDBC().getUserSelection(msg, "OK", items).toString();
	}
	/**
	 * Displays a message and a drop down menu
	 * @param msg The message to print
	 * @param items Elements in the drop down menu
	 * @param button The button
	 * @return the selected item
	 */
	public static String getUserDropDownSelection(String msg, String button, String[] items) {
		if(android) {
			return getABC().getInput(msg, false, true, items, new String[] {button})[2];
		}
		return getDBC().getUserSelection(msg, button, items).toString();
	}
	/**
	 * Sets the title of a field on the board.<br>
	 * @param fieldNumber
	 *        : int [1:40]
	 * @param title
	 *        : String (Mind the length!)
	 */
	public static void setTitleText(final int fieldNumber, final String title) {
		if(android) {
			getABC().setTitleText(fieldNumber, title);
		} else {
			getDBC().setTitleText(fieldNumber, title);
		}
	}
	/**
	 * Sets the subText of a field on the board.<br>
	 * @param fieldNumber
	 *        : int [1:40]
	 * @param subText
	 *        : String (Mind the length!)
	 */
	public static void setSubText(final int fieldNumber, final String subText) {
		if(android) {
			getABC().setSubText(fieldNumber, subText);
		} else {
			getDBC().setSubText(fieldNumber, subText);
		}
	}
	/**
	 * Sets the Description (The text shown in the center when mouse hovers) of
	 * a field on the board.<br>
	 * @param fieldNumber
	 *        : int [1:40]
	 * @param description
	 *        : String (Mind the length!)
	 */
	public static void setDescriptionText(final int fieldNumber, final String description) {
		if(android) {
			getABC().setDescriptionText(fieldNumber, description);
		} else {
			getDBC().setDescriptionText(fieldNumber, description);
		}
	}
	/**
	 * Adds a player to the board.<br>
	 * Max. 6 players.<br>
	 * @param playerName : String (Mind the length!) (Unique identifier of the player - no
	 *        duplicates)
	 * @param balance : int
	 */
	public static void addPlayer(final String playerName, final int balance) {
		if(android) {
			getABC().addPlayer(playerName, balance);
		} else {
			getDBC().addPlayer(playerName, balance);
		}
	}
	/**
	 * Adds a player to the board.<br>
	 * Max. 6 players.<br>
	 * @param name : String (Mind the length!) (Unique identifier of the player - no
	 *        duplicates)
	 * @param balance : int
	 * @param car : Car
	 *        Cars are created this way:<br>
	 *        Car car = new Car.Builder()<br>
	 *        .primaryColor(Color.MAGENTA)<br>
	 *        .secondaryColor(Color.BLUE)<br>
	 *        .typeTractor()<br>
	 *        .patternDotted()<br>
	 *        .Build();<br>
	 */
	public static void addPlayer(final String name, final int balance, final Car car) {
		if(android) {
			getABC().addPlayer(name, balance, car);
		} else {
			getDBC().addPlayer(name, balance, car);
		}
		
	}
	/**
	 * Sets the balance of a player if the player has been added.
	 * @param name The name of the player
	 * @param newBalance : int
	 */
	public static void setBalance(final String name, final int newBalance) {
		if(android) {
					getABC().setBalance(name, newBalance);
		} else {
			getDBC().setBalance(name, newBalance);
		}
	}
	/**
	 * Shows two dice on the board. The dice will have the specified values, but
	 * the placement is random.<br>
	 * @param faceValue1
	 *        : int [1:6]
	 * @param rotation1
	 *        : int [0:360]
	 * @param faceValue2
	 *        : int [1:6]
	 * @param rotation2
	 *        : int [0:360[
	 * @param x1
	 *        : int [0:11]
	 * @param y1
	 *        : int [0:11]
	 * @param x2
	 *        : int [0:11]
	 * @param y2
	 *        : int [0:11]<br>
	 *        (If a parameter is out of bounds nothing will happen!)
	 */
	public static void setDice(final int faceValue1, final int rotation1, final int x1,
		final int y1,
		final int faceValue2, final int rotation2, final int x2, final int y2) {
		if(android) {
			getABC().setDice(faceValue1, rotation1, x1, y1, faceValue2, rotation2,
				x2, y2);
		} else {
			getDBC().setDice(faceValue1, rotation1, x1, y1, faceValue2, rotation2,
				x2, y2);
		}
	}
	/**
	 * Shows two dice on the board. The dice will have the specified values, but
	 * the placement is random.<br>
	 * @param faceValue1
	 *        : int [1:6]
	 * @param faceValue2
	 *        : int [1:6]
	 * @param x1
	 *        : int [0:11]
	 * @param y1
	 *        : int [0:11]
	 * @param x2
	 *        : int [0:11]
	 * @param y2
	 *        : int [0:11]<br>
	 *        (If a parameter is out of bounds nothing will happen!)
	 */
	public static void setDice(final int faceValue1, final int x1, final int y1,
		final int faceValue2,
		final int x2, final int y2) {
		if(android) {
					getABC().setDice(faceValue1, x1, y1, faceValue2, x2, y2);
		} else {
			getDBC().setDice(faceValue1, x1, y1, faceValue2, x2, y2);
		}
	}
	/**
	 * Shows two dice on the board. The dice will have the specified values, but
	 * the placement is random.<br>
	 * @param faceValue1
	 *        : int [1:6]
	 * @param rotation1
	 *        : int [0:360]
	 * @param faceValue2
	 *        : int [1:6]
	 * @param rotation2
	 *        : int [0:360[<br>
	 *        (If a parameter is out of bounds nothing will happen!)
	 */
	public static void setDice(final int faceValue1, final int rotation1, final int faceValue2,
		final int rotation2) {
		if(android) {
					getABC().setDice(faceValue1, rotation1, faceValue2, rotation2);
		} else {
			getDBC().setDice(faceValue1, rotation1, faceValue2, rotation2);
		}
	}
	/**
	 * Shows two dice on the board. The dice will have the specified values, but
	 * the placement is random.<br>
	 * @param faceValue1
	 *        : int [1:6]
	 * @param faceValue2
	 *        : int [1:6]<br>
	 *        (If a parameter is out of bounds nothing will happen!) Uses
	 *        random rotation.
	 */
	public static void setDice(final int faceValue1, final int faceValue2) {
		if(android) {
					getABC().setDice(faceValue1, faceValue2);
		} else {
			getDBC().setDice(faceValue1, faceValue2);
		}
	}
	/**
	 * Sets the text to appear in the center and displays it.
	 * @param txt : String (Mind the length!)<br>
	 */
	public static void displayChanceCard(final String txt) {
		if(android) {
					getABC().displayChanceCard(txt);
		} else {
			getDBC().displayChanceCard(txt);
		}
	}
	/**
	 * Sets the text to appear in the center when calling displayChanceCard() and when the
	 * deck is pressed.
	 * @param txt : String (Mind the length!)<br>
	 */
	public static void setChanceCard(final String txt) {
		if(android) {
					getABC().setChanceCard(txt);
		} else {
			getDBC().setChanceCard(txt);
		}
	}
	/**
	 * Displays the current chance card text in the center.
	 */
	public static void displayChanceCard() {
		if(android) {
					getABC().displayChanceCard();
		} else {
			getDBC().displayChanceCard();
		}
	}
	/**
	 * Places a car on the field.<br>
	 * All cars can be placed on the same field.<br>
	 * A car can only be placed if the corresponding player has been added.<br>
	 * If a car is placed on the same field multiple times, nothing more
	 * happens.<br>
	 * A car can not be placed on multiple fields simultaneously.
	 * @param fieldNumber
	 *        : int [1:40]
	 * @param name
	 *        The name of the player
	 */
	public static void setCar(final int fieldNumber, final String name) {
		if(android) {
					getABC().setCar(fieldNumber, name);
		} else {
			getDBC().setCar(fieldNumber, name);
		}
	}
	/**
	 * Removes a car from the board.<br>
	 * If the car is not on the board, nothing happens.
	 * @param fieldNumber
	 *        : int [1:40]
	 * @param name
	 *        The name of the player
	 */
	public static void removeCar(final int fieldNumber, final String name) {
		if(android) {
					getABC().removeCar(fieldNumber, name);
		} else {
			getDBC().removeCar(fieldNumber, name);
		}
	}
	/**
	 * Removes all cars belonging to this player.
	 * @param name
	 *        The name of the player.
	 */
	public static void removeAllCars(final String name) {
		if(android) {
					getABC().removeAllCars(name);
		} else {
			getDBC().removeAllCars(name);
		}
	}
	/**
	 * Sets an owner of a field.<br>
	 * The field border will have the same color as the player. The owners name
	 * will be printed in the subText. If the field is not a street, shipping or
	 * a brewery nothing happens.<br>
	 * If the owner hasn't been added to the board, nothing happens.
	 * @param fieldNumber
	 *        : int [1:40]
	 * @param prefix
	 *        The text to put in front of the players name on the
	 *        description of a field that the player owns.
	 * @param name
	 *        The name of the player
	 * @param postfix
	 *        The text to put after of the players name on the description
	 *        of a field that the player owns.
	 */
	public static void setOwner(final int fieldNumber, final String prefix, final String name,
		final String postfix) {
		if(android) {
					getABC().setOwner(fieldNumber, prefix, name, postfix);
		} else {
			getDBC().setOwner(fieldNumber, prefix, name, postfix);
		}
	}
	/**
	 * Removes an owner from the field.<br>
	 * If the field has no owner, nothing happens.
	 * @param fieldNumber
	 *        : int [1:40]
	 */
	public static void removeOwner(final int fieldNumber) {
		if(android) {
					getABC().removeOwner(fieldNumber);
		} else {
			getDBC().removeOwner(fieldNumber);
		}
	}
	/**
	 * Sets houses from the street, and removes the hotel if one is present.<br>
	 * If houseCount is out of bounds, nothing happens.<br>
	 * If the field is not a street, nothing happens.<br>
	 * @param fieldNumber
	 *        : int [1:40]
	 * @param houseCount
	 *        : int [0:4]
	 */
	public static void setHouses(final int fieldNumber, final int houseCount) {
		if(android) {
					getABC().setHouses(fieldNumber, houseCount);
		} else {
			getDBC().setHouses(fieldNumber, houseCount);
		}
	}
	/**
	 * Sets whether or not a hotel should be on the street and removes all
	 * houses if any is present.<br>
	 * @param fieldNumber
	 *        : int [1:40]
	 * @param hasHotel
	 *        : boolean
	 */
	public static void setHotel(final int fieldNumber, final boolean hasHotel) {
		if(android) {
					getABC().setHotel(fieldNumber, hasHotel);
		} else {
			getDBC().setHotel(fieldNumber, hasHotel);
		}
	}
	
	/**
	 * Initializes the board using an array of fields.<br>
	 * Doesn't show the GUI.<br>
	 * If this method isn't the first method to be called it will
	 * have no result.<br>
	 * @param fields : Field[]<br>
	 *        Fields are created this way:<br>
	 *        Field f = new
	 *        Start.Builder().setTitle("Title").setBgColor(Color.RED).build()<br>
	 *        Depending on the type of field, various attributes can be set.<br>
	 *        The field types are as follows:<br>
	 *        ... new Tax.Builder().build();<br>
	 *        ... new Street.Builder().build();<br>
	 *        ... new Shipping.Builder().build();<br>
	 *        ... new Refuge.Builder().build();<br>
	 *        ... new Jail.Builder().build();<br>
	 *        ... new Chance.Builder().build();<br>
	 *        ... new Brewery.Builder().build();<br>
	 *        ... new Empty.Builder().build();<br>
	 */
	public static void create(IGUIField[] fields) {
		if(android) {
			ArrayList<AndroidField> list = new ArrayList<AndroidField>();
			for(IGUIField f : fields)
				list.add((AndroidField) f);
			GUIFieldFactory.createFieldsFromArrayList(list);
		}
		else {
			ArrayList<DesktopField> list = new ArrayList<DesktopField>();
			for(IGUIField f : fields)
				list.add((DesktopField) f);
			FieldFactory.createFieldsFromArrayList(list);
		}
	}
}
